﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Caliburn.Micro;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Windows;
using GTServices.Entities;
using GTServices.Model.Extensions;
using System.Text.RegularExpressions;
using System.Threading;


namespace GTServices.Model.CoRoutine
{
    public class ExecuteGrepRequestRoutine : IResult
    {
        public event EventHandler<ResultCompletionEventArgs> Completed;

        public GrepRequest Request { get; protected set; }
        public GrepResult Result { get; protected set; } 

        public ExecuteGrepRequestRoutine(GrepRequest request)
        {
            this.Request = request;
        }


        public void Execute(ActionExecutionContext context)
        {
            GTApplication.Instance.DataModel.GrepRequests.Add(Request);

            try
            {

                //Timestamp the request. 
                Request.Start = DateTime.Now;

                //we get the files here because we have a seperate thread incase the file manager needs to fetch stuff. Not the best way, i could do better if i wanted to muck with things. 
                var fileInfos = GTApplication.Instance.FilesModel.GetFilesByPath(Request.RootPath, Request.FileExtensions).ToList();

                //Create a results set. 
                List<MatchInfo> matches = new List<MatchInfo>();

                //Get all the langauges for the patterns. 
                var languages = Request.Patterns.Select(x => x.Language).Distinct();

                //Execute a grep per language/pattern combination. 

                languages.ForEach(x =>
                {
                    var patterns = Request.Patterns.Where(y => y.Language == x).ToList();

                    List<Entities.FileInfo> files = null;

                    if (x.Name.Equals("All", StringComparison.CurrentCultureIgnoreCase))
                    {
                        files = fileInfos;
                    }
                    else
                    {
                        files = fileInfos.Where(y => x.FileExtensions.Contains(y.FileExtension)).ToList();
                    }
                    if (files != null)
                    {
                        if (files.Count > 0)
                        {
                            GrepRoutine gfr = new GrepRoutine(files, patterns, Request.LinesBefore, Request.LinesAfter);
                            gfr.Completed += (z, args) =>
                            {
                                if (args.Error == null)
                                    matches.AddRange(gfr.Matches);
                                else
                                    throw args.Error;
                            };

                            gfr.Execute(null);
                        }
                        //No files to grep.. let's do the next language, so do nothing here we will drop to the next iteration. 
                    }
                    else
                    {
                        throw new ArgumentException("Null fileInfos..this shouldn't happen");
                    }
                });


                //Need to add the GrepRequest to the reference of the MatchInfo. 
                matches.Apply(x => x.GrepRequest = Request);

                //We are done! let's build the grep result. 
                Result = new GrepResult()
                {
                    GrepRequest = Request,
                    MatchInfos = matches,
                    TimeCompleted = DateTime.Now
                };


                if (Completed != null)
                {
                    Completed(this, new ResultCompletionEventArgs()); 
                }
            }
            catch(Exception e)
            {
                if (Completed != null)
                {
                    Completed(this, new ResultCompletionEventArgs() { Error = e });
                }
            }
        }
    }
}
